using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Imagination;
using Imagination.Physics;

namespace ImagineBalls
{
	public class Ball : Thing
	{
		//	adjusted for scale (sphere is 1 unit in diameter; pool balls are 5cm
		//private static Vector3		standardGravity = new Vector3(0, -196F, 0);
		private const float			bounceFactor = 1f;
		private const float         resistance = 0.99f;
		private const float         angularResistance = 0.99f;
		static readonly float       mass = 0.165f;
		private const float			minimumVerticalSpeed = 1.0f; 
        private Force               reverseGravity;
        public bool                 onGround;

        public static Model         BallModel;
        public static Texture2D[]   Textures;

        public int Number = 0;    // range from 0 - 15; 0 = cueball 

		public Ball(int ballType, Vector3 position)
		{
            Number = ballType;
			
//			(Mesh.Sphere(device, 0.5f, 15, 10));
//
//			Material mat = Ball.InitMaterial(GetBallColor(ballType));
//			mat.Diffuse = Color.Gray;
//			((MeshModel)model).AddMaterial(mat);
            
            this.position = position;
            Boundary = new BoundingSphere(this.position, 0.5f);
            Model = Ball.BallModel;

            //InitPhysics();
        }

        public void InitPhysics()
        {
			this.Velocity = this.AngularVelocity = Vector3.Zero;

            this.Orientation = Quaternion.Identity;// new Quaternion();// .RotationYawPitchRoll(((float) Math.PI / 2), 0, 0);
                //Quaternion.CreateFromRotationMatrix(Matrix.CreateRotationX(((float)Math.PI / 2)));
			this.Mass = Ball.mass;
			this.Inertia = InertiaCalculator.CalcSphere(mass, Boundary.Radius);
            //  forces
            //this.Forces.Add(PhysicalConstants.GetForceConstant("gravity"));
            reverseGravity = engine.Physics.GetConstant<Force>("reverseGravity");
        }
		
		public override void Update(GameTime gameTime)
		{
            float dt = (float)(gameTime.ElapsedGameTime.TotalSeconds);
            
            float ground = 0.1f;
			float tolerance = 0.1f;

			Vector3 oldPosition = position;
			base.Update(gameTime);

            float groundDistance = position.Y - (ground + Boundary.Radius);
			float yTravelled = position.Y - oldPosition.Y;

			if (groundDistance <= tolerance)
			{
                position.Y = ground + Boundary.Radius;

				float verticalVelocity = velocity.Y;

				//Vector3 myGravity = PhysicalConstants.GetVectorConstant("gravity") * (1 / PhysicalConstants.UnitScale) * mass;
				//Vector3 blah = (velocity - myGravity) * bounceFactor;

				//Force impactForce = new Force(blah, this);

                Force impactForce = new Force(new Vector3(0, -1 * verticalVelocity * bounceFactor, 0), this);
				impactForce.IsTemporary = true;

				forces.Add(impactForce);
				//velocity = new Vector3(velocity.X, 0, velocity.Z);
				velocity.Y = Math.Abs(velocity.Y * 0.2f);
				//velocity = new Vector3(velocity.X, -1 * bounceFactor * velocity.Y, velocity.Z);
			}

			//if (velocity.Y < minimumVerticalSpeed)
			//	velocity = Vector3.Empty;


			bool isOnGround = (groundDistance <= tolerance); //&& (groundDistance >= -tolerance);

            if (isOnGround)
            {
                if (!this.onGround)
                {
                    forces.Add(reverseGravity);
					onGround = true;

				}
                velocity *= resistance;
                angularVelocity *= resistance;

				// hack: rotation
				velocity += new Vector3(-moments.Z / 2, velocity.Y, moments.X / 2);
            }
            else
            {
                if (this.onGround)
                {
                    forces.Remove(reverseGravity);
                    onGround = false;
                }
            }

			if (position.X > 120 || position.X < -120)
			{
				position.X = position.X > 120 ? 120f : -120f;
				velocity = new Vector3(-1 * bounceFactor * velocity.X, velocity.Y, velocity.Z);
			}
			if (position.Z > 120 || position.Z < -120)
			{
				position.Z = position.Z > 120 ? 120f : -120f;
				velocity = new Vector3(velocity.X, velocity.Y, -1 * bounceFactor * velocity.Z);
			}


		}

        public override string ToString()
        {
            return string.Format("Ball [{0}]: pos({1})", this.ID, this.Position);
        }
	}
}
